package com.piece.core.web.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.util.AntPathMatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Slf4j
public class FilterHookManager {

    private static final AntPathMatcher pathMatcher = new AntPathMatcher();
    private Map<String, Set<FilterHook>> filterHookSetMap = new HashMap<>();
    private Map<String, FilterHook> filterHookMap;

    public FilterHookManager(Map<String, FilterHook> filterHookMap) {
        log.info("加载 FilterHookManager ...");
        this.filterHookMap = filterHookMap;
        this.init();
    }

    /**
     * 获取过滤器的所有钩子
     */
    private void init() {
        if (null != this.filterHookMap) {
            Iterator<Map.Entry<String, FilterHook>> it = this.filterHookMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, FilterHook> entry = it.next();
                log.info("加载 FilterHookManager --> {}", entry.getKey());

                FilterHook filterHook = entry.getValue();
                filterHook.initFilter();
                addFilterHook(filterHook);
            }
        }
    }

    /**
     * 添加钩子
     */
    public void addFilterHook(FilterHook filterHook) {
        String[] paths = filterHook.getFilterPath();
        if (null == paths) {
            paths = new String[]{"/**"};
        }
        for (String path : paths) {
            if (!this.filterHookSetMap.containsKey(path)) {
                Set<FilterHook> list = new HashSet<>();
                list.add(filterHook);
                this.filterHookSetMap.put(path, list);
            } else {
                this.filterHookSetMap.get(path).add(filterHook);
            }
        }
    }

    /**
     * 删除钩子
     */
    public void removeFilterHook(FilterHook hook) {
        Iterator<Map.Entry<String, Set<FilterHook>>> it = this.filterHookSetMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Set<FilterHook>> entry = it.next();
            entry.getValue().remove(hook);
        }
    }

    public List<FilterHook> getFilterHook(String path) {
        List<FilterHook> filterHooks = new ArrayList<>();
        Iterator<Map.Entry<String, Set<FilterHook>>> it = this.filterHookSetMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Set<FilterHook>> entry = it.next();
            if (this.pathMatcher.match(entry.getKey(), path)) {
                filterHooks.addAll(entry.getValue());
            }
        }

        filterHooks.stream().sorted(Comparator.comparing(FilterHook::getIndex));

        return filterHooks;
    }

    public Pair beforeFilter(HttpServletRequest request, HttpServletResponse response) {
        List<FilterHook> filterHook = getFilterHook(request.getServletPath());
        int size = filterHook.size();
        Pair pair = Pair.of(request, response);
        for (int i = 0; i < size; i++) {
            pair = filterHook.get(i).beforeFilter((HttpServletRequest) pair.getKey(), (HttpServletResponse) pair.getValue());
        }

        return pair;
    }

    public void afterFilter(HttpServletRequest request, HttpServletResponse response) {
        List<FilterHook> filterHook = getFilterHook(request.getServletPath());

        int size = filterHook.size();
        for (int i = size - 1; i >= 0; i--) {
            filterHook.get(i).afterFilter(request, response);
        }
    }
}
